package com.dorje.sys.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.dorje.sys.bean.Constants;
import com.dorje.sys.entity.User;
import com.dorje.sys.service.MenuService;
import com.dorje.sys.service.RoleService;
import com.dorje.sys.service.UserService;

/**
 * Subject验证的过程可以有效地划分分以下三个步骤： 1.收集Subject提交的身份和证明； 2.向Authenticating提交身份和证明；
 * 3.如果提交的内容正确，允许访问，否则重新尝试验证或阻止访问
 * Realm：可以有1个或多个Realm，可以认为是安全实体数据源，即用于获取安全实体的；
 * 可以是JDBC实现，也可以是LDAP实现，或者内存实现等等；由用户提供；
 * 注意：Shiro不知道你的用户/权限存储在哪及以何种格式存储；所以我们一般在应用中都需要实现自己的Realm
 * @author q
 * 
 */
@Component("shiroDbRealm")
public class ShiroDbRealm extends AuthorizingRealm {

	private final Logger logger = LoggerFactory.getLogger(ShiroDbRealm.class);

	@Autowired
	private UserService userService;
	
	@Autowired
	private RoleService roleService;
	
	@Autowired
	private MenuService menuService;

	public ShiroDbRealm() {
		//访问量小的情况下  
		// 认证֤
		super.setAuthenticationCacheName(Constants.authenticationCacheName);
		super.setAuthenticationCachingEnabled(false); // 如果为true  密码会被缓存
		// 授权
		super.setAuthorizationCacheName(Constants.authorizationCacheName);
		super.setAuthorizationCachingEnabled(false);
	}

	// 授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("doGetAuthorizationInfo");
		// 因为非正常退出，即没有显式调用 SecurityUtils.getSubject().logout()
				// (可能是关闭浏览器，或超时)，但此时缓存依旧存在(principals)，所以会自己跑到授权方法里。
		if(!SecurityUtils.getSubject().isAuthenticated()){
			SecurityUtils.getSubject().logout();
			return null;
		}
		User user = (User) principals.getPrimaryPrincipal();
		Integer userId = user.getId();
		if(userId == null){
			return null;
		}
		
		// 添加角色及权限信息
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		try {
			//获取当前用户所有的角色,
			info.addRoles(roleService.findRoleByUser(userId));
			System.out.println(menuService.findPermissionsByUserId(userId));
			info.addStringPermissions(menuService.findPermissionsByUserId(userId));
			
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		
		return info;
	}

	// 认证֤
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		User user = null;
		String userName = upToken.getUsername();
		System.out.println(userName);
		try {
			user = userService.findInfoByAccount(userName);
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		
		if(user != null){
			System.out.println("======================"+user);
			AuthenticationInfo authinfo = new SimpleAuthenticationInfo(user,user.getPassword(),getName());
			System.out.println(authinfo);
			return authinfo;
		}
		return null;
		
	}

}
